#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h>

// #define SOL

static int nthread = 1;
static int round = 0;

//pthread_cond_wait(&cond, &mutex);  // go to sleep on cond, releasing lock mutex
//pthread_cond_broadcast(&cond);     // wake up every thread sleeping on cond
// pthread_mutex_t lock;     // declare a lock
// pthread_mutex_init(&lock, NULL);   // initialize the lock
// pthread_mutex_lock(&lock);  // acquire lock
//pthread_mutex_unlock(&lock);  // release lock

struct barrier {
  pthread_mutex_t barrier_mutex;
  pthread_cond_t barrier_cond;
  int nthread;      // Number of threads that have reached this round of the barrier
  int round;     // Barrier round
} bstate;

static void
barrier_init(void)
{
  assert(pthread_mutex_init(&bstate.barrier_mutex, NULL) == 0);
  assert(pthread_cond_init(&bstate.barrier_cond, NULL) == 0);
  bstate.nthread = 0;
}

static void 
barrier()
{
    pthread_mutex_lock(&bstate.barrier_mutex);//进来先上锁
    bstate.nthread++;//表示来了一个线程
    if(bstate.nthread<nthread){
        pthread_cond_wait(&bstate.barrier_cond, &bstate.barrier_mutex);//如果小于线程数就阻塞
        //阻塞在这里
    }
    else{
        //都来了
        bstate.round++;
        bstate.nthread=0;//复位进入下一轮
        pthread_cond_broadcast(&bstate.barrier_cond);     // wake up every thread sleeping on cond
    }
    
    pthread_mutex_unlock(&bstate.barrier_mutex);//出去把broadcast锁上的再打开
}

static void *
thread(void *xa)
{
  long n = (long) xa;
  long delay;
  int i;

  for (i = 0; i < 20000; i++) {
    
    int t = bstate.round;//这是第几轮,每一轮都要等待执行完毕
    assert (i == t);
    //bstate.nthread=0;//每一个round都得初始化一下
    /*if(bstate.nthread == nthread){
        pthread_cond_broadcast(&bstate.barrier_cond);     // wake up every thread sleeping on cond
    }*/

    //pthread_mutex_lock(&bstate.barrier_mutex);
    barrier();//round++，每个线程到这里都会++，共享变量要加锁
    usleep(random() % 100);
    //pthread_cond_wait(&bstate.barrier_cond, &bstate.barrier_mutex);
    
  }
}

int
main(int argc, char *argv[])
{
  pthread_t *tha;
  void *value;
  long i;
  double t1, t0;

  if (argc < 2) {
    fprintf(stderr, "%s: %s nthread\n", argv[0], argv[0]);
    exit(-1);
  }
  nthread = atoi(argv[1]);//线程数
  tha = malloc(sizeof(pthread_t) * nthread);//线程号
  srandom(0);

  barrier_init();//锁和cond的初始化都在这里了
  //pthread_mutex_init(&bstate.barrier_mutex, NULL);

  for(i = 0; i < nthread; i++) {
    assert(pthread_create(&tha[i], NULL, thread, (void *) i) == 0);
  }
  for(i = 0; i < nthread; i++) {
    assert(pthread_join(tha[i], &value) == 0);
  }
  printf("OK; passed\n");
}
